package com.easyjava.builder;

import com.easyjava.bean.Constants;
import com.easyjava.bean.FieldInfo;
import com.easyjava.bean.TableInfo;
import com.easyjava.init.InitCascade;
import com.easyjava.utils.MyStringUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static com.easyjava.init.InitCascade.TABLE_INFO_MAP;

/**
 * @Author: 小闹心
 * @Description: mapper xml文件生成器
 * @DateTime: 2024/11/17 18:03
 **/
public class BuildMapperXml {
    private static final Logger logger = LoggerFactory.getLogger(BuildMapperXml.class);

    private static final String BASE_COLUMN_LIST = "Base_Column_List";

    private static final String BASE_QUERY_CONDITION = "Base_Query_Condition";

    private static final String BASE_QUERY_CONDITION_EXTEND = "Base_Query_Condition_Extend";
    private static final String QUERY_CONDITION = "Query_Condition";

    public static void execute(TableInfo tableInfo) {
        File folder = new File(Constants.PATH_MAPPER_XML);
        if (!folder.exists()) {
            folder.mkdirs();
        }
        String className = tableInfo.getBeanName() + Constants.SUFFIX_MAPPER;
        File file = new File(folder, className + ".xml");
        OutputStream out = null;
        OutputStreamWriter outWriter = null;
        BufferedWriter bw = null;
        try{
            out = new FileOutputStream(file);
            outWriter = new OutputStreamWriter(out, StandardCharsets.UTF_8);
            bw = new BufferedWriter(outWriter);
            bw.write("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
            bw.newLine();
            bw.write("<!DOCTYPE mapper");
            bw.newLine();
            bw.write("\tPUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"");
            bw.newLine();
            bw.write("\t\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">");
            bw.newLine();
            String poClass = Constants.PACKAGE_PO + "." + tableInfo.getBeanName();
            bw.write("<mapper namespace=\"" + Constants.PACKAGE_MAPPER + "." + className + "\">");
            bw.newLine();
            bw.newLine();
            bw.write("\t<!-- 通用查询映射结果 -->");
            bw.newLine();

            bw.write("\t<resultMap id=\"BaseResultMap\" type=\"" + poClass + "\">");
            bw.newLine();
            FieldInfo idField = null;
            List<FieldInfo> fieldInfoList = null;
            Map<String, List<FieldInfo>> keyIndexMap = tableInfo.getKeyIndexMap();
            for(Map.Entry<String, List<FieldInfo>> entry : keyIndexMap.entrySet()){
                if("PRIMARY".equals(entry.getKey())){
                    fieldInfoList = entry.getValue();
                    if(fieldInfoList.size() == 1){
                        idField = fieldInfoList.get(0);
                        break;
                    }
                }
            }
            for(FieldInfo fieldInfo : tableInfo.getFieldList()){
                bw.write("\t\t<!-- " + fieldInfo.getComment() + " -->");
                bw.newLine();
                String key = "result";
                if(idField != null && MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()).equals(idField.getPropertyName())){
                    key = "id";
                }
                bw.write("\t\t<" + key +" column=\"" + fieldInfo.getFieldName() + "\" property=\""+ MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + "\" />");
                bw.newLine();
            }
            bw.write("\t</resultMap>");
            bw.newLine();
            bw.newLine();

            bw.write("\t<!-- 通用查询结果集 -->");
            bw.newLine();
            bw.write("\t<sql id=\"" + BASE_COLUMN_LIST + "\">");
            bw.newLine();
            StringBuilder columnBuilder = new StringBuilder();
            for(FieldInfo fieldInfo : tableInfo.getFieldList()){
                columnBuilder.append(fieldInfo.getFieldName()).append(", ");
            }
            bw.write("\t\t" + columnBuilder.substring(0, columnBuilder.lastIndexOf(",")));
            bw.newLine();
            bw.write("\t</sql>");
            bw.newLine();
            bw.newLine();

            bw.write("\t<!-- 基础查询条件 -->");
            bw.newLine();
            bw.write("\t<sql id=\"" + BASE_QUERY_CONDITION + "\">");
            bw.newLine();
            for(FieldInfo fieldInfo : tableInfo.getFieldList()){
                String stringQuery = "";
                if(ArrayUtils.contains(Constants.SQL_STRING_TYPES, fieldInfo.getSqlType())){
                    stringQuery = " and query." + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + " != ''";
                }
                bw.write("\t\t<if test=\"query." + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + " != null" + stringQuery + "\">");
                bw.newLine();
                bw.write("\t\t\tand " + fieldInfo.getFieldName() + " = #{query." + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + "}");
                bw.newLine();
                bw.write("\t\t</if>");
                bw.newLine();
            }
            bw.write("\t</sql>");
            bw.newLine();
            bw.newLine();

            bw.write("\t<!-- 查询扩展条件 -->");
            bw.newLine();
            bw.write("\t<sql id=\"" + BASE_QUERY_CONDITION_EXTEND + "\">");
            bw.newLine();
            for(FieldInfo fieldInfo : tableInfo.getFieldExtendList()){
                String stringQuery = "";
                if(ArrayUtils.contains(Constants.SQL_STRING_TYPES, fieldInfo.getSqlType())){
                    stringQuery = " and query." + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + " != ''";
                }
                bw.write("\t\t<if test=\"query." + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + " != null" + stringQuery + "\">");
                bw.newLine();
                if(ArrayUtils.contains(Constants.SQL_STRING_TYPES, fieldInfo.getSqlType())){
                    bw.write("\t\t\tand " + fieldInfo.getFieldName() + " like concat('%', #{query." +
                            MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + "} , '%')");
                }
                if(ArrayUtils.contains(Constants.SQL_DATE_TYPES, fieldInfo.getSqlType()) || ArrayUtils.contains(Constants.SQL_DATE_TIMES_TYPES, fieldInfo.getSqlType())){
                    String bse = "<=";
                    if(MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()).contains(Constants.SUFFIX_BEAN_QUERY_TIME_START)){
                        bse = ">=";
                    }
                    bw.write("\t\t\t<![CDATA[ and " + fieldInfo.getFieldName() + " " + bse + " date_add(str_to_date(#{query." + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + "}, '%Y-%m-%d'), interval 1 day) ]]>");
                }
                bw.newLine();
                bw.write("\t\t</if>");
                bw.newLine();
            }
            bw.write("\t</sql>");
            bw.newLine();
            bw.newLine();

            bw.write("\t<!-- 通用查询条件 -->");
            bw.newLine();
            bw.write("\t<sql id=\"" + QUERY_CONDITION + "\">");
            bw.newLine();
            bw.write("\t\t<where>");
            bw.newLine();
            bw.write("\t\t\t<include refid=\"" + BASE_QUERY_CONDITION + "\"/>");
            bw.newLine();
            bw.write("\t\t\t<include refid=\"" + BASE_QUERY_CONDITION_EXTEND + "\"/>");
            bw.newLine();
            bw.write("\t\t</where>");
            bw.newLine();
            bw.write("\t</sql>");
            bw.newLine();
            bw.newLine();

            bw.write("\t<!-- 查询列表 -->");
            bw.newLine();
            bw.write("\t<select id=\"selectList\" resultMap=\"BaseResultMap\">");
            bw.newLine();
            bw.write("\t\tselect");
            bw.newLine();
            bw.write("\t\t\t<include refid=\"" + BASE_COLUMN_LIST + "\"/>");
            bw.newLine();
            bw.write("\t\tfrom " + tableInfo.getTableName());
            bw.newLine();
            bw.write("\t\t\t<include refid=\"" + QUERY_CONDITION + "\"/>");
            bw.newLine();
            bw.write("\t\t<if test=\"query.orderBy != null\">");
            bw.newLine();
            bw.write("\t\t\t\torder by ${query.orderBy}");
            bw.newLine();
            bw.write("\t\t</if>");
            bw.newLine();
            bw.write("\t\t<if test=\"query.simplePage != null\">");
            bw.newLine();
            bw.write("\t\t\t\tlimit #{query.simplePage.start}, #{query.simplePage.end}");
            bw.newLine();
            bw.write("\t\t</if>");
            bw.newLine();
            bw.write("\t</select>");
            bw.newLine();
            bw.newLine();

            bw.write("\t<!-- 查询数量 -->");
            bw.newLine();
            bw.write("\t<select id=\"selectCount\" resultType=\"java.lang.Integer\">");
            bw.newLine();
            bw.write("\t\tselect count(1) from " + tableInfo.getTableName());
            bw.newLine();
            bw.write("\t\t<include refid=\"" + QUERY_CONDITION + "\"/>");
            bw.newLine();
            bw.write("\t</select>");
            bw.newLine();
            bw.newLine();

            bw.write("\t<!-- 插入 (匹配有值的字段) -->");
            bw.newLine();
            bw.write("\t<insert id=\"insert\" parameterType=\"" + poClass + "\">");
            bw.newLine();
            FieldInfo autoIncrementField = null;
            for(FieldInfo fieldInfo : tableInfo.getFieldList()){
                if(fieldInfo.getAutoIncrement()){
                    autoIncrementField = fieldInfo;
                    break;
                }
            }
            // todo 可能bug
            if(autoIncrementField == null){
                bw.write("\t\t<selectKey keyProperty=\"bean." + autoIncrementField.getPropertyName() + "\" resultType=\"" +
                        autoIncrementField.getJavaType() + "\" order=\"AFTER\">");
                bw.newLine();
                bw.write("\t\t\tselect last_insert_id()");
                bw.newLine();
                bw.write("\t\t</selectKey>");
                bw.newLine();
            }
            bw.write("\t\tinsert into " + tableInfo.getTableName());
            bw.newLine();
            bw.write("\t\t<trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">");
            bw.newLine();
            for(FieldInfo fieldInfo : tableInfo.getFieldList()){
                bw.write("\t\t\t<if test=\"bean." + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + " != null\">");
                bw.newLine();
                bw.write("\t\t\t\t" + fieldInfo.getFieldName() + ",");
                bw.newLine();
                bw.write("\t\t\t</if>");
                bw.newLine();
            }
            bw.write("\t\t</trim>");
            bw.newLine();
            bw.write("\t\t<trim prefix=\"values (\" suffix=\")\" suffixOverrides=\",\">");
            bw.newLine();
            for(FieldInfo fieldInfo : tableInfo.getFieldList()){
                bw.write("\t\t\t<if test=\"bean." + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + " != null\">");
                bw.newLine();
                bw.write("\t\t\t\t#{bean." + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + "},");
                bw.newLine();
                bw.write("\t\t\t</if>");
                bw.newLine();
            }
            bw.write("\t\t</trim>");
            bw.newLine();
            bw.write("\t</insert>");
            bw.newLine();
            bw.newLine();

            /**
            bw.write("\t<!-- 插入或者更新(匹配有值的字段) -->");
            bw.newLine();
            bw.write("\t<insert id=\"insertOrUpdate\" parameterType=\"" + poClass + "\">");
            bw.newLine();
            bw.write("\t\tinsert into " + tableInfo.getTableName());
            bw.newLine();
            bw.write("\t\t<trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">");
            bw.newLine();
            for(FieldInfo fieldInfo : tableInfo.getFieldList()){
                bw.write("\t\t\t<if test=\"bean." + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + " != null\">");
                bw.newLine();
                bw.write("\t\t\t\t" + fieldInfo.getFieldName() + ",");
                bw.newLine();
                bw.write("\t\t\t</if>");
                bw.newLine();
            }
            bw.write("\t\t</trim>");
            bw.newLine();
            bw.write("\t\t<trim prefix=\"values (\" suffix=\")\" suffixOverrides=\",\">");
            bw.newLine();
            for(FieldInfo fieldInfo : tableInfo.getFieldList()){
                bw.write("\t\t\t<if test=\"bean." + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + " != null\">");
                bw.newLine();
                bw.write("\t\t\t\t#{bean." + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + "},");
                bw.newLine();
                bw.write("\t\t\t</if>");
                bw.newLine();
            }
            bw.write("\t\t</trim>");
            bw.newLine();
            bw.write("\t\ton duplicate key update");
            bw.newLine();
            bw.write("\t\t<trim prefix=\"\" suffix=\"\" suffixOverrides=\",\">");
            bw.newLine();
            StringBuilder insertFieldsBuilder = new StringBuilder();
            StringBuilder insertFieldsValueBuilder = new StringBuilder();
            for(FieldInfo fieldInfo : tableInfo.getFieldList()){
                bw.write("\t\t\t<if test=\"bean." + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + " != null\">");
                bw.newLine();
                bw.write("\t\t\t\t" + fieldInfo.getFieldName() + "= values(" + fieldInfo.getFieldName() + "),");
                bw.newLine();
                bw.write("\t\t\t</if>");
                bw.newLine();
                if(!fieldInfo.getAutoIncrement()){
                    insertFieldsBuilder.append(fieldInfo.getFieldName()).append(", ");
                    insertFieldsValueBuilder.append("#{item.").append(MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName())).append("}, ");
                }
            }
            bw.write("\t\t</trim>");
            bw.newLine();
            bw.write("\t</insert>");
            bw.newLine();
            bw.newLine();
             */
            /**
            bw.write("\t<!-- 批量插入 -->");
            bw.newLine();
            bw.write("\t<insert id=\"insertBatch\" parameterType=\"" + poClass + "\" useGeneratedKeys=\"true\" keyProperty=\"id\">");
            bw.newLine();
            bw.write("\t\tinsert into " + tableInfo.getTableName() + "(" + insertFieldsBuilder.substring(0,insertFieldsBuilder.lastIndexOf(",")) + ") values ");
            bw.newLine();
            bw.write("\t\t<foreach collection=\"list\" item=\"item\" separator=\",\">");
            bw.newLine();
            bw.write("\t\t\t(" + insertFieldsValueBuilder.substring(0,insertFieldsValueBuilder.lastIndexOf(",")) + ")");
            bw.newLine();
            bw.write("\t\t</foreach>");
            bw.newLine();
            bw.write("\t</insert>");
            bw.newLine();
            bw.newLine();



            if(autoIncrementField != null){
                insertFieldsBuilder.insert(0, autoIncrementField.getFieldName() + ", ");
                insertFieldsValueBuilder.insert(0,"#{item." + autoIncrementField.getPropertyName() + "}, ");
            } **/
            int index = 0;
            /**
            bw.write("\t<!-- 批量插入或更新 -->");
            bw.newLine();
            bw.write("\t<insert id=\"insertOrUpdateBatch\" parameterType=\"" + poClass + "\" useGeneratedKeys=\"true\" keyProperty=\"id\">");
            bw.newLine();
            bw.write("\t\tinsert into " + tableInfo.getTableName() + "(" + insertFieldsBuilder.substring(0,insertFieldsBuilder.lastIndexOf(",")) + ") values ");
            bw.newLine();
            bw.write("\t\t<foreach collection=\"list\" item=\"item\" separator=\",\">");
            bw.newLine();
            bw.write("\t\t\t(" + insertFieldsValueBuilder.substring(0,insertFieldsValueBuilder.lastIndexOf(",")) + ")");
            bw.newLine();
            bw.write("\t\t</foreach>");
            bw.newLine();
            bw.write("\t\ton duplicate key update");
            bw.newLine();

            for(FieldInfo fieldInfo : tableInfo.getFieldList()){
                index++;
                bw.write("\t\t" + fieldInfo.getFieldName() + " = values(" + fieldInfo.getFieldName() + ")");
                if(index < tableInfo.getFieldList().size()){
                    bw.write(",");
                }
                bw.newLine();
            }
            bw.write("\t</insert>");
            bw.newLine();
            bw.newLine();
            **/
            // 生成唯一索引方法
            for(Map.Entry<String, List<FieldInfo>> entry : keyIndexMap.entrySet()){
                List<FieldInfo> keyFields = entry.getValue();
                index = 0;
                StringBuilder methodName = new StringBuilder();
                StringBuilder methodParam = new StringBuilder();
                for(FieldInfo fieldInfo : keyFields){
                    index++;
                    methodName.append(MyStringUtils.upperCaseFirstLetter(MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName())));
                    methodParam.append(fieldInfo.getFieldName()).append("=#{").append(MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName())).append("}");
                    if(index < keyFields.size()){
                        methodName.append("And");
                        methodParam.append(" and ");
                    }
                }

                bw.write("\t<!-- 根据" + methodName + "查询对象 -->");
                bw.newLine();
                bw.write("\t<select id=\"selectBy" + methodName + "\" resultMap=\"BaseResultMap\">" );
                bw.newLine();
                bw.write("\t\tselect <include refid=\"" + BASE_COLUMN_LIST + "\"/> from " + tableInfo.getTableName() + " where " + methodParam);
                bw.newLine();
                bw.write("\t</select>");
                bw.newLine();
                bw.newLine();

                bw.write("\t<!-- 根据" + methodName + "更新对象 -->");
                bw.newLine();
                bw.write("\t<update id=\"updateBy" + methodName + "\" parameterType=\"" + poClass + "\">" );
                bw.newLine();
                bw.write("\t\tupdate " + tableInfo.getTableName());
                bw.newLine();
                bw.write("\t\t<set>");
                bw.newLine();
                for(FieldInfo fieldInfo : tableInfo.getFieldList()){
                    if(!fieldInfoList.isEmpty()){
                        if(fieldInfoList.contains(fieldInfo)){
                            continue;
                        }
                    }
                    bw.write("\t\t\t<if test=\"bean." + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + " != null\">");
                    bw.newLine();
                    bw.write("\t\t\t\t" + fieldInfo.getFieldName() + " = #{bean." + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + "},");
                    bw.newLine();
                    bw.write("\t\t\t</if>");
                    bw.newLine();
                }
                bw.write("\t\t</set>");
                bw.newLine();
                bw.write("\t\twhere " + methodParam);
                bw.newLine();
                bw.write("\t</update>");
                bw.newLine();
                bw.newLine();

                bw.write("\t<!-- 根据" + methodName + "删除对象 -->");
                bw.newLine();
                bw.write("\t<delete id=\"deleteBy" + methodName + "\">" );
                bw.newLine();
                bw.write("\t\tdelete from " + tableInfo.getTableName() + " where " + methodParam);
                bw.newLine();
                bw.write("\t</delete>");
                bw.newLine();
                bw.newLine();
            }

            String tableName = tableInfo.getTableName();
            List<String> tablesList = InitCascade.CASCADE_TABLE_MAP.get(tableName);
            if(tablesList != null){
                for(String tables : tablesList){
                    String[] cascadeTable = tables.split(",");
                    // 创建 resultMap
                    StringBuilder cascadeClass = new StringBuilder();
                    cascadeClass.append(MyStringUtils.upperCaseFirstLetter(cascadeTable[0]));
                    if(cascadeTable.length > 1){
                        cascadeClass.append("And");
                    }
                    for(int i = 1; i < cascadeTable.length;i++){
                        cascadeClass.append(MyStringUtils.upperCaseFirstLetter(TABLE_INFO_MAP.get(cascadeTable[i]).getBeanName()));
                        if(i != cascadeTable.length - 1){
                            cascadeClass.append("And");
                        }
                    }
                    bw.write("\t<!-- " + cascadeClass + "连表查询 -->");
                    bw.newLine();
                    bw.write("\t<resultMap id=\"select" + cascadeClass + "Map\" type=\"" + Constants.PACKAGE_VO + "." + cascadeClass + "\">");
                    bw.newLine();

                    for(FieldInfo fieldInfo : tableInfo.getFieldList()){
                        bw.write("\t\t<!-- " + fieldInfo.getComment() + " -->");
                        bw.newLine();
                        String key = "result";
                        if(idField != null && MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()).equals(idField.getPropertyName())){
                            key = "id";
                        }
                        bw.write("\t\t<" + key +" column=\"" + fieldInfo.getFieldName() + "\" property=\""+ MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + "\" />");
                        bw.newLine();
                    }
                    String fieldAndRelation = InitCascade.CASCADE_FIELD_RELATION_MAP.get(tables);
                    if(fieldAndRelation != null){
                        String[] fieldAndRelationArray = fieldAndRelation.split(" ");
                        String[] relations = fieldAndRelationArray[1].split("\\|");
                        List<Integer> mnTables = new ArrayList<>();
                        for(int i = 1;i < cascadeTable.length;i++){
                            if(relations[i - 1].contains("-n") || relations[i - 1].contains("-m")){
                                mnTables.add(i);
                                continue;
                            }
                            TableInfo curTableInfo = TABLE_INFO_MAP.get(cascadeTable[i]);
                            bw.write("\t\t<association property=\"" + MyStringUtils.lowerCaseFirstLetter(curTableInfo.getBeanName()) + "\" javaType=\"" + Constants.PACKAGE_PO + "." + MyStringUtils.upperCaseFirstLetter(curTableInfo.getBeanName()) + "\">");
                            bw.newLine();
                            FieldInfo curIdField = null;
                            List<FieldInfo> curFieldInfoList = null;
                            Map<String, List<FieldInfo>> curKeyIndexMap = curTableInfo.getKeyIndexMap();
                            for(Map.Entry<String, List<FieldInfo>> entry : curKeyIndexMap.entrySet()){
                                if("PRIMARY".equals(entry.getKey())){
                                    curFieldInfoList = entry.getValue();
                                    if(curFieldInfoList.size() == 1){
                                        curIdField = curFieldInfoList.get(0);
                                        break;
                                    }
                                }
                            }
                            for(FieldInfo fieldInfo : curTableInfo.getFieldList()){
                                bw.write("\t\t\t<!-- " + fieldInfo.getComment() + " -->");
                                bw.newLine();
                                String key = "result";
                                if(curIdField != null && MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()).equals(curIdField.getPropertyName())){
                                    key = "id";
                                }
                                bw.write("\t\t\t<" + key +" column=\"" + curTableInfo.getTableName() + "_" + fieldInfo.getFieldName() + "\" property=\""+ MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + "\" />");
                                bw.newLine();
                            }

                            bw.write("\t\t</association>");
                            bw.newLine();
                        }
                        for(Integer i : mnTables){
                            TableInfo curTableInfo = TABLE_INFO_MAP.get(cascadeTable[i]);
                            bw.write("\t\t<collection property=\"" + MyStringUtils.lowerCaseFirstLetter(curTableInfo.getBeanName()) + "\" ofType=\"" + Constants.PACKAGE_PO + "." + MyStringUtils.upperCaseFirstLetter(curTableInfo.getBeanName()) + "\">");
                            bw.newLine();
                            FieldInfo curIdField = null;
                            List<FieldInfo> curFieldInfoList = null;
                            Map<String, List<FieldInfo>> curKeyIndexMap = curTableInfo.getKeyIndexMap();
                            for(Map.Entry<String, List<FieldInfo>> entry : curKeyIndexMap.entrySet()){
                                if("PRIMARY".equals(entry.getKey())){
                                    curFieldInfoList = entry.getValue();
                                    if(curFieldInfoList.size() == 1){
                                        curIdField = curFieldInfoList.get(0);
                                        break;
                                    }
                                }
                            }
                            for(FieldInfo fieldInfo : curTableInfo.getFieldList()){
                                bw.write("\t\t\t<!-- " + fieldInfo.getComment() + " -->");
                                bw.newLine();
                                String key = "result";
                                if(curIdField != null && MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()).equals(curIdField.getPropertyName())){
                                    key = "id";
                                }
                                bw.write("\t\t\t<" + key +" column=\"" + curTableInfo.getTableName() + "_" + fieldInfo.getFieldName() + "\" property=\""+ MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + "\" />");
                                bw.newLine();
                            }

                            bw.write("\t\t</collection>");
                            bw.newLine();
                        }

                    }

                    bw.newLine();
                    bw.write("\t</resultMap>");
                    bw.newLine();

                    bw.write("\t<select id=\"select" + cascadeClass + "\" resultMap=\"select" + cascadeClass + "Map\">");
                    bw.newLine();

                    StringBuilder curCascadeTable = new StringBuilder();
                    curCascadeTable.append(cascadeTable[0]);
                    if(cascadeTable.length > 1){
                        curCascadeTable.append("_and_");
                    }
                    for(int i = 1; i < cascadeTable.length; i++){
                        curCascadeTable.append(cascadeTable[i]);
                        if(i != cascadeTable.length - 1){
                            curCascadeTable.append("_and_");
                        }
                    }

                    if(fieldAndRelation != null) {
                        String[] fieldAndRelationArray = fieldAndRelation.split(" ");
                        String[] relations = fieldAndRelationArray[0].split("\\|");
                        String cascadeTableSql = getCascadeTableSql(curCascadeTable.toString(), relations, relations.length - 1);
                        bw.write("\t\t" + cascadeTableSql);
                        bw.newLine();
                    }
                    bw.write("\t</select>");
                    bw.newLine();

                }
            }


            bw.write("</mapper>");
            bw.newLine();
            bw.flush();
        }catch (Exception e){
            logger.error("创建MAPPER_XML文件失败");
            e.printStackTrace();
        }finally {
            if(bw != null){
                try {
                    bw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(outWriter != null){
                try {
                    outWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(out != null){
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private static String getCascadeTableSql(String cascadeTable, String[] cascadeFields, int i){
        // 分割 成两个表 last _
        int last_ = cascadeTable.lastIndexOf("_and_");
        if(last_ == -1){
            return cascadeTable;
        }
        String firstTable = cascadeTable.substring(0, last_);
        String secondTable = cascadeTable.substring(last_ + "_and_".length());
        String[] cascadeField = cascadeFields[i].split("&");
        StringBuilder sql = new StringBuilder("select " + firstTable + ".*");
        TableInfo tableInfo = TABLE_INFO_MAP.get(secondTable);
        for(FieldInfo fieldInfo : tableInfo.getFieldList()){
            sql.append(",").append(secondTable).append(".").append(fieldInfo.getFieldName()).append(" as ").append(secondTable).append("_").append(fieldInfo.getFieldName());
        }
        sql.append(" from ");
        sql.append(getCascadeTableSql(firstTable, cascadeFields, i - 1)).append(" left join ").append(secondTable).append(" on ");
        for(int j = 0;j < cascadeField.length;j++){
            String[] f = cascadeField[j].split("-");
            sql.append(firstTable).append(".");
            if(firstTable.contains("_and_")){
                sql.append(firstTable.substring(firstTable.lastIndexOf("_and_") + "_and_".length())).append("_");
            }
            sql.append(f[0]).append(" = ").append(secondTable).append(".").append(f[1]);
            if(j != cascadeField.length - 1){
                sql.append(" and ");
            }
        }
        return i == cascadeFields.length - 1 ? sql.toString() : "(" + sql.toString() + ") as " + cascadeTable;
    }
}
